﻿using System;
using System.IO;

namespace StateLoader
{
    class StateLoader
    {
        static void Main(string[] args)
        {
            try
            {
                PrintMap(args[0]);
                PrintState(args[1]);
                PrintStepInvocation();
            }
            catch(Exception ex)
            {
                Console.Error.WriteLine("Error: {0}", ex.Message);
            }
        }

        private static void PrintMap(string mapFileName)
        {
            string[] mapLines = File.ReadAllText(mapFileName).Trim().Split('\n');
            for (int i = 0; i < mapLines.Length; ++i)
                mapLines[i] = mapLines[i].Trim();

            int[,] map = new int[mapLines.Length, mapLines[0].Length];
            int h = mapLines.Length;
            int w = mapLines[0].Length;
            for (int y = 0; y < h; ++y)
            {
                if (mapLines[y].Length != w)
                    throw new Exception("bad map");
                Console.WriteLine("; Map line {0}", y);
                for (int x = 0; x < w; ++x)
                    Console.WriteLine("LDC {0}", GetValue(mapLines[y][x]));

                Console.WriteLine("LDC 0");

                for (int x = 0; x < w; ++x)
                    Console.WriteLine("CONS");
                Console.WriteLine("");
            }

            Console.WriteLine("LDC 0");

            Console.WriteLine("; join map lines");
            for (int y = 0; y < h; ++y)
                Console.WriteLine("CONS");
            Console.WriteLine("");
        }

        private static int GetValue(char c)
        {
            switch(c)
            {
                default:
                    throw new Exception("bad character");
                case '#':
                    return 0;
                case ' ':
                    return 1;
                case '.':
                    return 2;
                case 'o':
                    return 3;
                case '%':
                    return 4;
                case '\\':
                    return 5;
                case '=':
                    return 6;
            }
        }

        private static void PrintState(string stateFileName)
        {
            string[] mapLines = File.ReadAllText(stateFileName).Trim().Split('\n');
            int lineIndex = 0;
            int subLineIndex = 0;
            int numGhosts = 0;

            foreach (var l in mapLines)
            {
                string line = l;
                var commentPos = line.IndexOf(';');
                if (commentPos >= 0)
                    line = line.Substring(0, commentPos);
                line = line.Trim();
                if (line.Length == 0)
                    continue;

                bool done = false;
                while (!done)
                {
                    done = true;
                    switch (lineIndex)
                    {
                        default:
                            throw new Exception("Too many lines in config");
                        case 0: // man
                            PrintManStatus(line);
                            ++lineIndex;
                            break;
                        case 1: // number of ghosts
                            numGhosts = int.Parse(line);
                            ++lineIndex;
                            subLineIndex = 0;
                            if (numGhosts == 0)
                                done = false;
                            break;
                        case 2: // ghost
                            if (subLineIndex < numGhosts)
                            {
                                PrintGhost(subLineIndex, line);
                                ++subLineIndex;
                            }

                            if (subLineIndex == numGhosts)
                            {
                                Console.WriteLine("LDC 0");
                                if (numGhosts > 0)
                                    Console.WriteLine("; joining ghosts");
                                for (int i = 0; i < numGhosts; ++i)
                                    Console.WriteLine("CONS");
                                Console.WriteLine("");
                                ++lineIndex;
                            }
                            break;
                        case 3: // fruit status
                            PrintFruitStatus(line);
                            ++lineIndex;
                            break;
                    }
                }
            }

            if (lineIndex != 4)
                throw new Exception("Bad data format");

            Console.WriteLine("; Joining everything");
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("");
        }

        private static void PrintManStatus(string line)
        {
            string[] fields = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            if (fields.Length != 6)
                throw new Exception("Bad man state");

            Console.WriteLine("; Lambda-man state");
            Console.WriteLine("LDC {0} ; vitality", int.Parse(fields[0]));
            Console.WriteLine("LDC {0} ; x", int.Parse(fields[1]));
            Console.WriteLine("LDC {0} ; y", int.Parse(fields[2]));
            Console.WriteLine("CONS");
            Console.WriteLine("LDC {0} ; direction", int.Parse(fields[3]));
            Console.WriteLine("LDC {0} ; lives", int.Parse(fields[4]));
            Console.WriteLine("LDC {0} ; score", int.Parse(fields[5]));
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("");
        }

        private static void PrintGhost(int ghostIndex, string line)
        {
            Console.WriteLine("; Ghost #{0}", ghostIndex);
            string[] fields = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            if (fields.Length != 4)
                throw new Exception("Bad ghost state");

            Console.WriteLine("LDC {0} ; vitality", int.Parse(fields[0]));
            Console.WriteLine("LDC {0} ; x", int.Parse(fields[1]));
            Console.WriteLine("LDC {0} ; y", int.Parse(fields[2]));
            Console.WriteLine("CONS");
            Console.WriteLine("LDC {0} ; direction", int.Parse(fields[3]));
            Console.WriteLine("CONS");
            Console.WriteLine("CONS");
            Console.WriteLine("");
        }

        private static void PrintFruitStatus(string line)
        {
            Console.WriteLine("; Fruit status (expiry countdown)");
            Console.WriteLine("LDC {0}", int.Parse(line));
            Console.WriteLine("");
        }

        private static void PrintStepInvocation()
        {
            Console.WriteLine("LDF __invoke_main_and_step__");
            Console.WriteLine("TAP 1");
            Console.WriteLine("");
            Console.WriteLine("__invoke_main_and_step__:");
            Console.WriteLine("LD 0 0 ; world state");
            Console.WriteLine("LDC 1 ; \"undefined\"");
            Console.WriteLine("LDF MainFunction");
            Console.WriteLine("AP 2");
            Console.WriteLine("LDF __invoke_step__");
            Console.WriteLine("TAP 1");
            Console.WriteLine("");
            Console.WriteLine("__invoke_step__:");
            Console.WriteLine("LD 0 0");
            Console.WriteLine("CAR");
            Console.WriteLine("LD 1 0");
            Console.WriteLine("LD 0 0");
            Console.WriteLine("CDR");
            Console.WriteLine("AP 2");
            Console.WriteLine("RTN");
            Console.WriteLine("");
        }
    }
}
